/**
 * e-fuli.com Inc.
 * Copyright (c) 2015-2018 All Rights Reserved.
 */
package efuliBusiness.ebuyOpenPlatformUtil;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;

import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * <pre>
 * 签名工具类
 * </pre>
 *
 * @author jiangjin
 * @version $Id: SignatureUtil.java, v 0.1 2018年3月8日 下午5:17:20 jiangjin Exp $
 */
public final class SignatureUtil {

    private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

    /** 指定加密算法为RSA */
    private static final String ALGORITHM = "RSA";

    /** 密钥长度，用来初始化 */
    private static final int KEYSIZE = 2048;

    public static final String PUBLIC_KEY = "publicKey";

    public static final String PRIVATE_KEY = "privateKey";

    /**
     * 签名
     * @param privateKey
     *            私钥
     * @param text
     *            明文
     * @return
     */
    public static byte[] sign(PrivateKey privateKey, String text) throws Exception {
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(text.getBytes("UTF-8"));

        return signature.sign();
    }

    /**
     * 验签
     * @param publicKey
     *            公钥
     * @param text
     *            明文
     * @param signed
     *            签名
     */
    public static boolean verifySign(PublicKey publicKey, String text, byte[] signed) throws Exception {
        Signature verifySign = Signature.getInstance(SIGNATURE_ALGORITHM);
        verifySign.initVerify(publicKey);
        verifySign.update(text.getBytes("UTF-8"));
        return verifySign.verify(signed);
    }

    /**
     * bytes[]换成16进制字符串
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * <pre>
     * 字符串转公钥
     * </pre>
     * @param publicKeyPerm
     * @return
     */
    public static RSAPublicKey str2PublicKey(String publicKeyPerm) {
        try {
            // Only RSAPublicKeySpec and X509EncodedKeySpec supported for RSA public keys
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64Util.decodeBase64(publicKeyPerm));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * <pre>
     * 字符串转私钥
     * </pre>
     * @param privateKeyPerm
     * @return
     */
    public static RSAPrivateKey str2PrivateKey(String privateKeyPerm) {
        try {
            // Only RSAPrivate(Crt)KeySpec and PKCS8EncodedKeySpec supported for RSA private keys
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64Util.decodeBase64(privateKeyPerm));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * <pre>
     * 拼接字符串
     * </pre>
     * @param requestParams
     * @return
     */
    public static String getSignContent(Map<String, String> requestParams) {
        StringBuilder content = new StringBuilder();
        List<String> keys = new ArrayList<String>(requestParams.keySet());
        Collections.sort(keys);
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = requestParams.get(key);
            // 过滤空值和sign字段
            if (StringUtils.isBlank(value) || key.equals("sign")) {
                continue;
            }
            if (i > 0) {
                content.append("&");
            }
            content.append(humpToLine(key) + "=" + value);
        }
        return content.toString();
    }
    
    /** 驼峰转下划线 */
    public static String humpToLine(String str) {
        Pattern humpPattern = Pattern.compile("[A-Z]");
        Matcher matcher = humpPattern.matcher(str);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    public static Map<String, String> genKeyPair() throws NoSuchAlgorithmException {

        Map<String, String> keys = new HashMap<String, String>();

        /** RSA算法要求有一个可信任的随机数源 */
        SecureRandom secureRandom = new SecureRandom();

        /** 为RSA算法创建一个KeyPairGenerator对象 */
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);

        /** 利用上面的随机数据源初始化这个KeyPairGenerator对象 */
        keyPairGenerator.initialize(KEYSIZE, secureRandom);

        /** 生成密匙对 */
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        /** 得到公钥 */
        Key publicKey = keyPair.getPublic();

        /** 得到私钥 */
        Key privateKey = keyPair.getPrivate();

        String publicKeyBase64 = Base64.encodeBase64String(publicKey.getEncoded());
        String privateKeyBase64 = Base64.encodeBase64String(privateKey.getEncoded());

        keys.put(PUBLIC_KEY, publicKeyBase64);
        keys.put(PRIVATE_KEY, privateKeyBase64);
        return keys;
    }
}
